﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using UnityEditor;
using UnityEngine;

public class SkillTableEditor : EditorWindow
{
    Vector2 scrollPos;
    Vector2 scrollEditPos;
    PropertyInfo[] properties;
    List<skills_raw> skillDatas = new List<skills_raw>();
    int currentSelectIndex = 0;
    List<bool> toggleValues = new List<bool>();
    List<int> widths = new List<int>();
    skills_raw tempModifyData;
    List<string> tempModifyDataValues;
    [MenuItem("Tools/Excel/SkillTableEditor")]
    public static void GetWindow()
    {
        var window = EditorWindow.GetWindow<SkillTableEditor>(true, "技能编辑");
        window.minSize = new Vector2(1800, 300);
        window.Show();
    }

    private void OnEnable()
    {
        skillDatas.Add(new skills_raw() { id = 1, loc_skill_name = "LOC_DASH", skill_type = 1, state_mask = 11, prepare_time = 0 });
        skillDatas.Add(new skills_raw() { id = 2, loc_skill_name = "LOC_SUPER_JUMP", skill_type = 2, state_mask = 3, prepare_time = 0.5f });
        properties = typeof(skills_raw).GetProperties();
    }

    private GUIStyle GetStyle(int section, TextAnchor anchor = TextAnchor.MiddleCenter, int fontSize = 12)
    {
        return new GUIStyle()
        {
            alignment = anchor,
            fontSize = fontSize,
            normal = new GUIStyleState()
            {
                textColor = new Color(1, 1, 1),
            },
        };
    }

    private int GetCurrentProperityWidth(int section, int defaultWidth = 30)
    {
        return (properties[section].Name.Length / 5 + 1) * defaultWidth;
    }

    private void OnGUI()
    {
        GUILayout.Space(30);
        DrawTableDatas();
        GUILayout.Space(30);

        if (currentSelectIndex > 0)
        {
            GUILayout.Label(new GUIContent("编辑区域"), new GUIStyle()
            {
                alignment = TextAnchor.MiddleLeft,
                fontSize = 16,
                normal = new GUIStyleState()
                {
                    textColor = new Color(1, 1, 1),
                }
            });
            GUILayout.Space(30);
            //显示title
            GUILayout.BeginHorizontal();
            for (int section = 0; section < NumberOfSectionsInTableView(); section++)
            {
                GUILayout.Label(new GUIContent(properties[section].Name), GetStyle(section), GUILayout.Width(GetCurrentProperityWidth(section, 33)));
            }
            GUILayout.EndHorizontal();
            GUILayout.Space(20);
            //显示数据
            GUILayout.BeginHorizontal();
            for (int i = 0; i < properties.Length; i++)
            {
                tempModifyDataValues[i] = EditorGUILayout.TextField(tempModifyDataValues[i], GetStyle(i), GUILayout.Width(GetCurrentProperityWidth(i, 33)));
            }
            GUILayout.EndHorizontal();
            GUILayout.Space(20);
            GUILayout.BeginHorizontal();
            if (GUILayout.Button("保存数据到Excel"))
            {
                if (tempModifyData != null)
                {
                    //var mBuilder = new ExcelConverter();
                    //List<ExcelDataValue[]> values = new List<ExcelDataValue[]>();
                    //List<string> attributesStringValues = new List<string>();
                    //var assembly = typeof(skills_exceldata).Assembly;
                    //for (int i = 0; i < properties.Length; i++)
                    //{
                    //    var v = properties[i].GetValue(tempModifyData);
                    //    foreach (var m in GetExtensionMethods(assembly, v.GetType()))
                    //    {
                    //        if (m.Name.Contains("GetSaveToExcelStringValue"))
                    //        {
                    //            var stringValue = m.Invoke(null, new object[] { v });
                    //            attributesStringValues.Add(stringValue.ToString());
                    //        }
                    //    }
                    //}
                    //var attributesValues = attributesStringValues.ToArray();
                    //ExcelDataValue[] datavalues = new ExcelDataValue[attributesValues.Length];
                    //for (int i = 0; i < attributesValues.Length; i++)
                    //{
                    //    datavalues[i] = new ExcelDataValue(attributesValues[i]);
                    //}
                    //values.Add(datavalues);
                    //mBuilder.WriteDatas("skills", values);
                    Debug.Log("保存修改");
                }
                else
                {
                    Debug.LogError("没有选择要编辑保存的数据");
                }
            }
            if (GUILayout.Button("Excel -> Sqlite"))
            {
                //BDFramework.Editor.BDEditorMenu.ExecuteExcel2SQLite();
            }
            if (GUILayout.Button("保存测试数据"))
            {
                Debug.Log("测试数据");
                SaveModityDataToTempSkillData();
                //Game.Data.skills_raw.SetTestData(tempModifyData);
                if (tempModifyData.id > skillDatas.Count)
                {
                    skillDatas.Add(tempModifyData);
                }
                currentSelectIndex = 0;
            }
            GUILayout.EndHorizontal();
        }
        else
        {
            GUILayout.Label(new GUIContent("选择某一行编辑数据"), new GUIStyle() { fontSize = 16, normal = new GUIStyleState() { textColor = new Color(0.8f, 0, 0) } });
            if (GUILayout.Button("添加数据"))
            {
                tempModifyData = new skills_raw()
                {
                    id = skillDatas.Count + 1,
                    loc_skill_name = "LOC_DASH",
                    skill_type = 1,
                    state_mask = 3,
                    prepare_time = 0,
                    duration = 1,
                    end_time = 0,
                    accept_move_control = false,
                    follow_move_dir = true,
                    move_speed = Vector3.zero,
                    disable_gravity = false,
                    jump_height = 0,
                    projectile_id = 0,
                    projectile_dir = Vector3.zero,
                    //weapon_projectile_index = 1,
                    skill_param_1 = 0,
                    skill_param_2 = 0,
                    skill_param_3 = 0,
                };

                GetDataStringValues();
                currentSelectIndex = tempModifyData.id;
                toggleValues[0] = false;
            }
        }
    }

    IEnumerable<MethodInfo> GetExtensionMethods(Assembly assembly,
       Type extendedType)
    {
        var query = from type in assembly.GetTypes()
                    where type.IsSealed && !type.IsGenericType && !type.IsNested
                    from method in type.GetMethods(BindingFlags.Static
                        | BindingFlags.Public | BindingFlags.NonPublic)
                    where method.IsDefined(typeof(ExtensionAttribute), false)
                    where method.GetParameters()[0].ParameterType == extendedType
                    select method;
        return query;
    }

    private void GetDataStringValues()
    {
        if (tempModifyDataValues == null)
            tempModifyDataValues = new List<string>();
        else
            tempModifyDataValues.Clear();
        for (int i = 0; i < properties.Length; i++)
        {
            var value = properties[i].GetValue(tempModifyData);
            if (value == null)
            {
                throw new Exception("对象字段值不存在");
            }
            tempModifyDataValues.Add(value.ToString());
        }
    }

    /// <summary>
    /// convert string to Type
    /// </summary>
    /// <param name="obj"></param>
    /// <param name="type"></param>
    /// <returns></returns>
    private object ConvertObject(object obj, Type type)
    {
        if (type == null) return obj;
        if (obj == null) return type.IsValueType ? Activator.CreateInstance(type) : null;

        Type underlyingType = Nullable.GetUnderlyingType(type);
        if (type.IsAssignableFrom(obj.GetType())) // 如果待转换对象的类型与目标类型兼容，则无需转换
        {
            return obj;
        }
        else if ((underlyingType ?? type).IsEnum) // 如果待转换的对象的基类型为枚举
        {
            if (underlyingType != null && string.IsNullOrEmpty(obj.ToString())) // 如果目标类型为可空枚举，并且待转换对象为null 则直接返回null值
            {
                return null;
            }
            else
            {
                return Enum.Parse(underlyingType ?? type, obj.ToString());
            }
        }
        else if (typeof(IConvertible).IsAssignableFrom(underlyingType ?? type)) // 如果目标类型的基类型实现了IConvertible，则直接转换
        {
            try
            {
                return Convert.ChangeType(obj, underlyingType ?? type, null);
            }
            catch
            {
                return underlyingType == null ? Activator.CreateInstance(type) : null;
            }
        }
        else if (type.IsAssignableFrom(typeof(Vector3)))
        {
            string v = obj.ToString();
            v = v.Replace("(", "").Replace(")", "");
            var strValues = v.Split(',');
            return new Vector3(Convert.ToSingle(strValues[0]), Convert.ToSingle(strValues[1]), Convert.ToSingle(strValues[2]));
        }
        else
        {
            TypeConverter converter = TypeDescriptor.GetConverter(type);
            if (converter.CanConvertFrom(obj.GetType()))
            {
                return converter.ConvertFrom(obj);
            }
            ConstructorInfo constructor = type.GetConstructor(Type.EmptyTypes);
            if (constructor != null)
            {
                object o = constructor.Invoke(null);
                PropertyInfo[] propertys = type.GetProperties();
                Type oldType = obj.GetType();
                foreach (PropertyInfo property in propertys)
                {
                    PropertyInfo p = oldType.GetProperty(property.Name);
                    if (property.CanWrite && p != null && p.CanRead)
                    {
                        property.SetValue(o, ConvertObject(p.GetValue(obj, null), property.PropertyType), null);
                    }
                }
                return o;
            }
        }
        return obj;
    }

    private void SaveModityDataToTempSkillData()
    {
        for (int i = 0; i < properties.Length; i++)
        {
            var v = ConvertObject(tempModifyDataValues[i], properties[i].PropertyType);
            properties[i].SetValue(tempModifyData, v);
        }
    }

    void DrawTableDatas()
    {
        EditorGUILayout.BeginHorizontal();
        scrollPos = EditorGUILayout.BeginScrollView(scrollPos, GUILayout.Width(1850), GUILayout.Height(350));
        EditorGUILayout.BeginHorizontal();
        if (toggleValues.Count < 1)
            toggleValues.Add(true);
        if (toggleValues[0] = EditorGUILayout.Toggle(toggleValues[0]))
        {
            if (currentSelectIndex != 0)
            {
                ChangeSelect(0);
            }
        }
        widths.Clear();
        for (int i = 0; i < properties.Length; i++)
        {
            int w = (properties[i].Name.Length / 5 + 1) * 34;
            widths.Add(w);
            EditorGUILayout.LabelField(properties[i].Name, GUILayout.Width(w));
        }
        EditorGUILayout.EndHorizontal();
        for (int i = 0; i < skillDatas.Count; i++)
        {
            EditorGUILayout.BeginHorizontal();
            if (toggleValues.Count <= i + 1)
                toggleValues.Add(false);
            if (toggleValues[i + 1] = EditorGUILayout.Toggle(toggleValues[i + 1]))
            {
                if (currentSelectIndex != i + 1)
                {
                    ChangeSelect(i + 1);
                }
            }
            var data = skillDatas[i];
            for (int j = 0; j < properties.Length; j++)
            {
                EditorGUILayout.LabelField(properties[j].GetValue(data).ToString(), GUILayout.Width(widths[j]));
            }
            EditorGUILayout.EndHorizontal();
        }
        EditorGUILayout.EndScrollView();
        EditorGUILayout.EndHorizontal();
    }

    void ChangeSelect(int index)
    {
        if (toggleValues.Count < 1)
            throw new Exception("没有toggle组");
        if (index < 0 || index > toggleValues.Count - 1)
            throw new Exception("toggle索引超过范围");

        if (currentSelectIndex != index && currentSelectIndex <= skillDatas.Count)
        {
            toggleValues[currentSelectIndex] = false;
            toggleValues[index] = true;
        }
        currentSelectIndex = index;
        Debug.Log("选择" + index);
        if (index > 0)
        {
            tempModifyData = skillDatas[index - 1];
            GetDataStringValues();
        }
    }
    int NumberOfSectionsInTableView()
    {
        return properties.Length;
    }
}
